package com.dsg.controller.apply;


import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.ExcelWriter;
import com.alibaba.excel.write.metadata.WriteSheet;
import com.alibaba.excel.write.metadata.fill.FillWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.OrderItem;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.dsg.common.constants.MessageConstants;
import com.dsg.common.dto.AjaxResult;
import com.dsg.common.security.SystemAuthorizingUser;
import com.dsg.common.util.DateUtils;
import com.dsg.common.util.FileUtils;
import com.dsg.common.util.SingletonLoginUtils;
import com.dsg.common.util.UUIDGenerator;
import com.dsg.common.util.toolbox.CollectionUtil;
import com.dsg.common.util.toolbox.StringUtil;
import com.dsg.controller.base.BaseController;
import com.dsg.entity.apply.*;
import com.dsg.entity.approve.DsgApproveCase;
import com.dsg.entity.coupon.DsgCouponSend;
import com.dsg.entity.dto.CardTypeDto;
import com.dsg.entity.dto.RejectCarDto;
import com.dsg.entity.dto.ReturnCardRecordDto;
import com.dsg.entity.model.apply.DsgApplyCarModel;
import com.dsg.entity.system.DsgSysFile;
import com.dsg.entity.system.DsgSysParameter;
import com.dsg.service.apply.*;
import com.dsg.service.approve.IDsgApproveCaseService;
import com.dsg.service.coupon.IDsgCouponSendService;
import com.dsg.service.oil.IDsgOilInfoService;
import com.dsg.service.set.IDsgSetCarBacklistService;
import com.dsg.service.set.IDsgSetCusBacklistService;
import com.dsg.service.set.IDsgSetPayBacklistService;
import com.dsg.service.system.IDsgSysFileService;
import com.dsg.service.system.IDsgSysParameterService;
import com.dsg.support.LeveldbAccess;
import com.dsg.util.DsgUtils;
import com.dsg.util.RRException;
import com.dsg.util.SnowflakeKeyWorker;
import com.dsg.workflow.WorkflowEngine;
import com.dsg.workflow.WorkflowService3;
import io.swagger.annotations.*;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.compress.archivers.ArchiveEntry;
import org.apache.commons.compress.archivers.zip.Zip64Mode;
import org.apache.commons.compress.archivers.zip.ZipArchiveEntry;
import org.apache.commons.compress.archivers.zip.ZipArchiveOutputStream;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletResponse;
import java.io.ByteArrayOutputStream;
import java.io.OutputStream;
import java.net.URLEncoder;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.stream.Collectors;

/**
 * <p>
 * 車輛資料 前端控制器
 * </p>
 *
 * @author system
 * @since 2020-07-04
 */
@RestController
@RequestMapping("/apply/dsgApplyCar")
@Slf4j
@Api(description = "車輛資料")
public class DsgApplyCarController extends BaseController {

    @Autowired
    private IDsgApplyCarService service;
    @Autowired
    private IDsgApplyEnclService enclService;
    @Autowired
    private IDsgSysFileService fileService;
    @Autowired
    private IDsgApplyCardService cardService;
    @Autowired
    private IDsgApplyDiscountService discountService;
    @Autowired
    private IDsgCouponSendService couponSendService;
    @Autowired
    private IDsgApplyQuestionService questionService;
    @Autowired
    private IDsgSysParameterService dsgSysParameterService;
    @Autowired
    IDsgApplyCusService cusService;
    @Autowired
    IDsgApplyBillService billService;
    @Autowired
    IDsgSetCusBacklistService cusBacklistService;
    @Autowired
    IDsgSetCarBacklistService carBacklistService;
    @Autowired
    IDsgApplyComService comService;
    @Autowired
    IDsgApplyPayService payService;
    @Autowired
    IDsgSetPayBacklistService payBacklistService;
    @Autowired
    IDsgApproveCaseService caseService;
    @Autowired
    IDsgApplyStatusService statusService;
    @Autowired
    WorkflowEngine engine;
    @Autowired
    IDsgOilInfoService oilInfoService;

    @GetMapping(value = "/cancelCar")
    @ApiOperation("錄入車輛資料-取消")
    public AjaxResult cancelCar(String carOid) throws Exception {
        DsgApplyCar car = service.getById(carOid);
        if (DsgApplyCar.CAR_STATUS_NOT_RECORD != car.getCarStatus()) {
            throw new Exception("只有未錄入狀態才能取消");
        }
        car.setCarStatus(DsgApplyCar.CAR_STATUS_CANCEL);
        service.updateById(car);
        return success();
    }

    @GetMapping(value = "/selectRejectCar")
    @ApiOperation("拒絕車列表")
    @ApiResponses({
            @ApiResponse(response = RejectCarDto.class, code = 1, message = "ok")
    })
    public AjaxResult selectRejectCar(DsgApplyCar applyCar) {
        Page page = getPage();
        applyCar.setEntCode(getEntCode());
        page = service.selectRejectCar(page, applyCar);
        AjaxResult ajaxResult = json(MessageConstants.SSO_STATUS_SUCCESS, page.getRecords(), (int) page.getTotal());
        return ajaxResult;
    }

    @GetMapping(value = "/getCarList")
    @ApiOperation("客戶資料-客戶資料-選擇車輛")
    public AjaxResult getCarList(String cusNo) {
        QueryWrapper wrapper = new QueryWrapper();
        wrapper.eq("CUS_NO", cusNo);
        List<DsgApplyCar> carList = service.list(wrapper);
        return success(carList);
    }

    @PutMapping(value = "/edit")
    @ApiOperation("重新编辑")
    public AjaxResult edit(String appNo) {
        QueryWrapper wrapper = new QueryWrapper();
        wrapper.eq("APP_NO", appNo);
        List<DsgApplyCar> carList = service.list(wrapper);
        carList.forEach(e -> e.setVerify(DsgApplyCar.VERIFY_NO));
        service.updateBatchById(carList);
        return success();
    }

    @PutMapping(value = "/verify")
    @ApiOperation("完成核对")
    public AjaxResult verify(String appNo) {
        QueryWrapper wrapper = new QueryWrapper();
        wrapper.eq("APP_NO", appNo);
        List<DsgApplyCar> carList = service.list(wrapper);
        carList.forEach(e -> e.setVerify(DsgApplyCar.VERIFY_YES));
        service.updateBatchById(carList);
        return success();
    }

    @Transactional(rollbackFor = Exception.class)
    @PutMapping(value = "/saveDetail")
    @ApiOperation("录入车辆资料界面，保存车辆明细(補齊車輛資料-保存)")
    public AjaxResult saveDetail(@RequestBody DsgApplyCar applyCar) throws Exception {
        applyCar.setCarStatus(DsgApplyCar.CAR_STATUS_RECORD);
        service.updateById(applyCar);

        DsgApplyCar car = service.getById(applyCar.getOid());
        QueryWrapper wrapper = new QueryWrapper();
        wrapper.eq("APP_NO", car.getAppNo());
        wrapper.eq("CAR_STATUS", DsgApplyCar.CAR_STATUS_NOT_RECORD);
        //todo 做内审，让拒绝单可以重新对单
//        DsgApproveCase approveCase = caseService.getCase(WorkflowService3.NODE_CHECK_LIST, car.getAppNo());
//        if (approveCase == null) {
            if (service.count(wrapper) == 0) {
                DsgApproveCase case1 = caseService.getCase(WorkflowService3.NODE_INPUT_CAR_INFO, car.getAppNo());
                if (case1 != null && case1.getStatus() == DsgApproveCase.Status.started.getCode()) {
                    log.info("workflow forward: {}", case1.getTaskId());
                    engine.forward(case1);
                }

                wrapper = new QueryWrapper();
                wrapper.eq("APP_NO", car.getAppNo());
                DsgApplyBill bill = billService.getOne(wrapper);
                billService.internalAudit(bill);
            }
//        } else {
//            wrapper = new QueryWrapper();
//            wrapper.eq("APP_NO", car.getAppNo());
//            DsgApplyBill bill = billService.getOne(wrapper);
//            boolean pass = billService.internalAudit(bill);
//            if (pass) {
//                bill.setAppStatus(DsgApplyBill.APP_STATUS_1);
//                billService.updateById(bill);
//            }
//        }

        return json(MessageConstants.SSO_STATUS_SUCCESS, car);
    }

    @Autowired
    private IDsgApplyStatusService dsgApplyStatusService;
    @Autowired
    private LeveldbAccess leveldbAccess;

    @GetMapping(value = "/list")
    @ApiOperation("查询列表（分页）")
    public AjaxResult list(DsgApplyCar applyCar) {
        QueryWrapper wrapper = new QueryWrapper();
        wrapper.eq("MAIN_NO", applyCar.getMainNo());
        List<DsgApplyCar> list = service.list(wrapper);
        AjaxResult ajaxResult = json(MessageConstants.SSO_STATUS_SUCCESS, list);
        return ajaxResult;
    }

    @GetMapping(value = "/selectPage")
    @ApiOperation("查询列表")
    public AjaxResult selectPage(DsgApplyCar applyCar) {
        Page page = getPage();
        applyCar.setEntCode(getEntCode());
        applyCar.setUserId(SingletonLoginUtils.getSystemUserId());
        page = service.selectByList(page, applyCar);
        AjaxResult ajaxResult = json(MessageConstants.SSO_STATUS_SUCCESS, page.getRecords(), (int) page.getTotal());
        return ajaxResult;
    }

    /**
     * 查询单条数据
     *
     * @param id
     * @return
     */
    @GetMapping(value = "/{id}/view")
    @ApiOperation("查询单条数据")
    public AjaxResult view(@PathVariable String id) {
        DsgApplyCar applyCar = service.getById(id);
        return json(MessageConstants.SSO_STATUS_SUCCESS, applyCar);
    }

    @GetMapping(value = "/{id}/detail")
    @ApiOperation("查询单条数据")
    public AjaxResult detail(@PathVariable String id) {
        DsgApplyCar applyCar = service.detail(id);
        return json(MessageConstants.SSO_STATUS_SUCCESS, applyCar);
    }

    /**
     * 新增
     *
     * @param applyCar
     * @return
     */
    @PostMapping(value = "/add")
    @ApiOperation("新增")
    public AjaxResult add(@RequestBody DsgApplyCar applyCar) {
        if (StringUtil.isEmpty(applyCar.getCarNo())) {
            return fail("車牌號碼不能為空");
        }
        QueryWrapper wrapper = new QueryWrapper();
        wrapper.eq("CAR_NO", applyCar.getCarNo());
        if (service.count(wrapper) > 0) {
            return setErrorJson("已存在該車牌的資料");
        }

        wrapper = new QueryWrapper();
        wrapper.eq("APP_NO", applyCar.getAppNo());
        DsgApplyBill bill = billService.getOne(wrapper);
        String carNo = applyCar.getCarNo();
        carNo = StringUtil.isNotEmpty(carNo) ? carNo.toUpperCase() : "";
        if (carNo.startsWith("FV") && carNo.startsWith("ZG") && carNo.startsWith("F") && carNo.startsWith("AM") && carNo.startsWith("ETC")) {
            bill.setAppStatus(DsgApplyBill.APP_STATUS_2);
            billService.save(bill);
        }

        applyCar.setOid(UUIDGenerator.getUUID());
        service.save(applyCar);
        return json(MessageConstants.SSO_STATUS_SUCCESS, applyCar);
    }

    /**
     * @param applyCar
     * @return
     */
    @PutMapping(value = "/saveOrUpdate")
    @ApiOperation("新增或更新")
    @Transactional(rollbackFor = Exception.class)
    public AjaxResult saveOrUpdate(@RequestBody DsgApplyCar applyCar) throws Exception {
        if (StringUtil.isEmpty(applyCar.getAppNo())) {
            return fail("appNo不能为空");
        }

        if (StringUtil.isEmpty(applyCar.getCarNo())) {
            return fail("車牌號不能为空");
        }

//        if (StringUtil.isEmpty(applyCar.getCusNo())) {
//            return fail("公司/個人資料編號不能为空");
//        }

//        if (null == applyCar.getOwnsType()) {
//            return fail("資料類型ownsType不能为空");
//        }

        QueryWrapper wrapper = new QueryWrapper();
        wrapper.eq("MAIN_NO", applyCar.getMainNo());
        wrapper.eq("APP_NO", applyCar.getAppNo());
        DsgApplyBill bill = billService.getOne(wrapper);

        String carNo = applyCar.getCarNo();
        carNo = StringUtil.isNotEmpty(carNo) ? carNo.toUpperCase() : "";
        if (carNo.startsWith("FV") && carNo.startsWith("ZG") && carNo.startsWith("F") && carNo.startsWith("AM") && carNo.startsWith("ETC")) {
            bill.setAppStatus(DsgApplyBill.APP_STATUS_2);
        }

        if (StringUtil.isEmpty(applyCar.getOid())) {
            applyCar.setOid(UUIDGenerator.getUUID());
            applyCar.setMainNo(applyCar.getMainNo());
            applyCar.setAppNo(applyCar.getAppNo());
        }
        service.saveOrUpdate(applyCar);

        if (bill.getAppType() == DsgApplyBill.APP_TYPE_4) {
            wrapper = new QueryWrapper();
            wrapper.eq("APP_NO", applyCar.getAppNo());
            wrapper.eq("CAR_ID", applyCar.getOid());
            List<DsgApplyCard> cardList = cardService.list(wrapper);
            for (DsgApplyCard card : cardList) {
                wrapper = new QueryWrapper();
                wrapper.eq("APP_NO", applyCar.getAppNo());
                wrapper.eq("CARD_ID", card.getOid());
                DsgApplyStatus status = statusService.getOne(wrapper);
                if (status != null && StringUtil.isEmpty(status.getCarNo())) {
                    status.setCarNo(applyCar.getCarNo());
                    statusService.updateById(status);
                } else if (status == null){
                    status = new DsgApplyStatus();
                    status.setOid(UUIDGenerator.getUUID());
                    status.setAppStatus(DsgApplyStatus.APP_STATUS_DRAFT);
                    status.setAppNo(applyCar.getAppNo());
                    status.setCardId(card.getOid());
                    status.setCarNo(applyCar.getCarNo());
                    status.setAppType(applyCar.getAppType());
                    statusService.save(status);
                }
            }
        } else {//CS轉車牌不用去變更歸屬於該車的其它信息
            wrapper = new QueryWrapper();
            wrapper.select("OID");
            wrapper.eq("CAR_ID", applyCar.getOid());
            List<DsgApplyCard> preCardList = cardService.list(wrapper);
            List<String> preCardOids = null;
            List<String> cardOids = null;
            if (CollectionUtil.isNotEmpty(preCardList)) {
                preCardOids = preCardList.stream().map(DsgApplyCard::getOid).collect(Collectors.toList());
            }

            List<DsgApplyCard> cardList = applyCar.getCardList();
            if (CollectionUtils.isNotEmpty(cardList)) {
                cardOids = cardList.stream().map(DsgApplyCard::getOid).collect(Collectors.toList());
                if (CollectionUtil.isNotEmpty(preCardOids) && CollectionUtil.isNotEmpty(cardOids)) {
                    preCardOids.removeAll(cardOids);
                }
                if (CollectionUtil.isNotEmpty(preCardOids)) {
                    cardService.removeByIds(preCardOids);
                    for (String preCardOid :
                            preCardOids) {
                        wrapper = new QueryWrapper();
                        wrapper.eq("CARD_ID", preCardOid);
                        discountService.remove(wrapper);
                        couponSendService.remove(wrapper);
                    }
                }

                for (DsgApplyCard card :
                        cardList) {
                    if (StringUtil.isEmpty(card.getOid())) {
//                        card.setOwnsType(applyCar.getOwnsType());
                        card.setCusNo(applyCar.getCusNo());
                        card.setCarId(applyCar.getOid());
                        card.setAppNo(applyCar.getAppNo());
                        card.setOid(UUIDGenerator.getUUID());
                        CardTypeDto dto = new CardTypeDto();
                        if (DsgApplyCard.CARD_CLASSIFY_CASH == card.getCardClassify()) {
                            dto.setCardType(card.getCardType1());
                        } else {
                            dto.setCardType(card.getCardType());
                        }
                        dto.setEntCode(getEntCode());
                        String oilCom = oilInfoService.getOilComByCardType(dto);
                        if (StringUtil.isEmpty(oilCom)) {
                            throw new Exception("沒有配置油公司资料");
                        }
                        card.setOilCom(oilCom);

                        //由於沒有對單環節，需要在這裏設定付款資料
                        if (bill.getAppType() == DsgApplyBill.APP_TYPE_4 ||
                                bill.getAppType() == DsgApplyBill.APP_TYPE_5) {
                            card.setPayId(bill.getPayId());
                            card.setMainPayId(bill.getPayId());
                        }

                        DsgApplyStatus status = new DsgApplyStatus();
                        status.setOid(UUIDGenerator.getUUID());
                        status.setAppStatus(DsgApplyStatus.APP_STATUS_DRAFT);
                        status.setAppNo(applyCar.getAppNo());
                        status.setCardId(card.getOid());
                        status.setCarNo(applyCar.getCarNo());
                        status.setAppType(applyCar.getAppType());
                        statusService.save(status);
                    }

                    wrapper = new QueryWrapper();
                    wrapper.select("OID");
                    wrapper.eq("CARD_ID", card.getOid());
                    List<DsgApplyDiscount> preDiscountList = discountService.list(wrapper);
                    List<String> preOids = null;
                    List<String> oids = null;
                    if (CollectionUtil.isNotEmpty(preDiscountList)) {
                        preOids = preDiscountList.stream().map(DsgApplyDiscount::getOid).collect(Collectors.toList());
                    }

                    List<DsgApplyDiscount> discountList = card.getDiscountList();
                    if (CollectionUtils.isNotEmpty(discountList)) {
                        oids = discountList.stream().map(DsgApplyDiscount::getOid).collect(Collectors.toList());
                        for (DsgApplyDiscount discount :
                                discountList) {
                            if (StringUtil.isEmpty(discount.getOid())) {
                                discount.setOid(UUIDGenerator.getUUID());
                                discount.setCardId(card.getOid());
                                discount.setDisStatus(DsgApplyDiscount.AppStatus.pendingApproval.getCode());
                                discount.setDisTarget(DsgApplyDiscount.DIS_TARGET_CARD);
                            }
                        }
                        discountService.saveOrUpdateBatch(discountList);
                    }

                    if (CollectionUtil.isNotEmpty(preOids)) {
                        if (CollectionUtil.isNotEmpty(oids)) {
                            preOids.removeAll(oids);
                        }
                        if (CollectionUtil.isNotEmpty(preOids)) {
                            discountService.removeByIds(preOids);
                        }
                    }

                    DsgCouponSend couponSend = card.getCoupon();
                    if (couponSend != null) {
                        if (StringUtil.isEmpty(couponSend.getOid())) {
                            couponSend.setOid(UUIDGenerator.getUUID());
                            couponSend.setCardId(card.getOid());
                            couponSend.setAppNo(applyCar.getAppNo());
                        }
                        couponSendService.saveOrUpdate(couponSend);
                    } else {
                        wrapper = new QueryWrapper();
                        wrapper.eq("CARD_ID", card.getOid());
                        couponSendService.remove(wrapper);
                    }
                }
                cardService.saveOrUpdateBatch(cardList);
            }

            wrapper = new QueryWrapper();
            wrapper.eq("CAR_ID", applyCar.getOid());
            questionService.remove(wrapper);
            DsgApplyQuestion question = applyCar.getQuestion();
            if (question != null) {
                if (StringUtil.isEmpty(question.getOid())) {
                    question.setOid(UUIDGenerator.getUUID());
                    question.setCarId(applyCar.getOid());
                    question.setQueType(DsgApplyQuestion.QUE_TYPE_CAR);
                }
                questionService.saveOrUpdate(question);
            }
        }

        return json(MessageConstants.SSO_STATUS_SUCCESS, applyCar);
    }

    @DeleteMapping(value = "{id}/delete")
    @ApiOperation("删除")
    public AjaxResult deleteOne(@PathVariable String id) {
        LambdaUpdateWrapper<DsgSysFile> wrapper = new LambdaUpdateWrapper();
        wrapper.eq(DsgSysFile::getRelId, id);
        fileService.remove(wrapper);

        service.removeById(id);
        return result(MessageConstants.SSO_STATUS_SUCCESS);
    }

    @DeleteMapping(value = "{id}/deleteCarAndOther")
    @ApiOperation("删除")
    public AjaxResult deleteCarAndOther(@PathVariable String id) {
//        log.info("成功删除{}", service.deleteCarAndOther(id));
        service.deleteCarAndOther(id);
        return result(MessageConstants.SSO_STATUS_SUCCESS);
    }

    @GetMapping(value = "/{mainNo}/getByBill")
    @ApiOperation("查询单条数据")
    public AjaxResult getByBill(@PathVariable String mainNo) {
        QueryWrapper wrapper = new QueryWrapper();
        wrapper.eq("MAIN_NO", mainNo);
        DsgApplyCar applyCus = service.getOne(wrapper);
        return json(MessageConstants.SSO_STATUS_SUCCESS, applyCus);
    }

    @GetMapping(value = "/{mainNo}/listByBill")
    @ApiOperation("查询单条数据")
    public AjaxResult listByBill(@PathVariable String mainNo) {
        QueryWrapper wrapper = new QueryWrapper();
        wrapper.eq("MAIN_NO", mainNo);
        List<DsgApplyCar> carList = service.list(wrapper);

        if (CollectionUtils.isNotEmpty(carList)) {
            for (DsgApplyCar car :
                    carList) {
                wrapper = new QueryWrapper();
                wrapper.eq("CAR_ID", car.getOid());
                List<DsgApplyCard> cardList = cardService.list(wrapper);
                if (CollectionUtils.isNotEmpty(cardList)) {
                    for (DsgApplyCard card :
                            cardList) {
                        wrapper = new QueryWrapper();
                        wrapper.eq("CARD_ID", card.getOid());
                        List<DsgApplyDiscount> discountList = discountService.list(wrapper);
                        card.setDiscountList(discountList);
                    }
                    car.setCardList(cardList);
                }

                wrapper = new QueryWrapper();
                wrapper.eq("CAR_ID", car.getOid());
                DsgApplyQuestion question = questionService.getOne(wrapper);
                car.setQuestion(question);
            }
        }

        return json(MessageConstants.SSO_STATUS_SUCCESS, carList);
    }


    /**
     * Check車牌列表（分页）
     *
     * @param dsgApplyCar
     * @return
     */
    @GetMapping(value = "/selectDsgApplyCarList")
    @ApiOperation("Check車牌列表（分页）")
    public AjaxResult selectDsgApplyCarList(DsgApplyCar dsgApplyCar) {
        // 分页
        Page page = getPage();
        String sort = getParameter("sort");
        List<OrderItem> orderItemList = new ArrayList<>();
        if (StringUtil.isEmpty(sort)) {
            orderItemList.add(new OrderItem().setColumn("b.APPLY_TIME").setAsc(false));
            page.setOrders(orderItemList);
        }
        dsgApplyCar.setEntCode(SingletonLoginUtils.getSystemEntCode());
        dsgApplyCar.setNodeName(WorkflowService3.NODE_CHECK_CAR_NO);
        page = service.selectDsgApplyCarList(page, dsgApplyCar);
        // 格式要返回的数据
        AjaxResult ajaxResult = json(MessageConstants.SSO_STATUS_SUCCESS, page.getRecords(), (int) page.getTotal());
        return ajaxResult;
    }

    @GetMapping(value = "/exportCheckCar")
    @ApiOperation(value = "導出Check車牌")
    @ApiResponses({
            @ApiResponse(response = Boolean.class, code = 1, message = "ok")
    })
    @Transactional(rollbackFor = {Exception.class, RuntimeException.class})
    public void exportCheckCarExcel(DsgApplyCar dsgApplyCar, HttpServletResponse response) throws Exception {
        if (dsgApplyCar == null || dsgApplyCar.getCardClassify() == null) {
            throw new RRException("油咭分類不能為空");
        }
        SystemAuthorizingUser user = SingletonLoginUtils.getSystemUser();
        dsgApplyCar.setEntCode(user.getOrgCode());
        dsgApplyCar.setNodeName(WorkflowService3.NODE_CHECK_CAR_NO);
        dsgApplyCar.setCheckStatus(DsgApplyStatus.AppStatus.untreated.getCode());
        dsgApplyCar.setUserId(user.getUserId());
        response.setContentType("application/zip");
        response.setCharacterEncoding("utf-8");
        String fileName = "Check車牌_" + user.getInputCopName() + "_" + DateUtils.getStringDate() + ".zip";
        response.setHeader("Content-disposition", "attachment; filename=" + URLEncoder.encode(fileName, "utf-8"));
        OutputStream out = response.getOutputStream();
        //壓縮
        ZipArchiveOutputStream zous = new ZipArchiveOutputStream(out);
        zous.setUseZip64(Zip64Mode.AsNeeded);
        zous.setEncoding("utf-8");
        //批次號
        String batchNo = user.getOrgCode() + "-" + DateUtils.getDate();
        String date = DateUtils.getDate();
        List<DsgApplyStatus> dsgApplyStatusList = new ArrayList<>();
        String templateFileName = "";
        //判斷選擇導出的模板
        switch (user.getOrgCode()) {
            case "HB":
                templateFileName = FileUtils.getExcelTemplatePath("checkCarHB.xlsx");
                break;
            case "HBC":
                templateFileName = FileUtils.getExcelTemplatePath("checkCarHBC.xlsx");
                break;
            case "PDL":
                templateFileName = FileUtils.getExcelTemplatePath("checkCarPDL.xlsx");
                break;
            default:
                break;
        }
        //按油公司分別導出EXCEL
        List<DsgApplyCar> dsgApplyCarList = service.selectDsgApplyCarList(dsgApplyCar);
        if (CollectionUtil.isNotEmpty(dsgApplyCarList)) {
            Map<String, List<DsgApplyCar>> dsgApplyCarMap = dsgApplyCarList.stream().collect(Collectors.groupingBy(I -> I.getOilComNo()));
            for (String oilComKey : dsgApplyCarMap.keySet()) {
                List<DsgApplyCar> listAll = dsgApplyCarMap.get(oilComKey);
                String checkBatchNo = batchNo + "-" + DsgUtils.getUUID();
                Integer serialNumber = 0;
                for (DsgApplyCar dac : listAll) {
                    dac.setCheckBatchNo(checkBatchNo);
                    DsgApplyStatus dsgApplyStatus = new DsgApplyStatus();
                    dsgApplyStatus.setOid(dac.getStatusID());
                    dsgApplyStatus.setCheckStatus(DsgApplyStatus.AppStatus.haveInHand.getCode());
                    dsgApplyStatus.setCheckBatchNo(checkBatchNo);
                    serialNumber++;
                    dac.setSerialNumber(serialNumber);
                    dsgApplyStatusList.add(dsgApplyStatus);
                }
                List<DsgApplyCar> list = new ArrayList<>();
                //以車牌號去重
                listAll.stream().filter(distinctByKey(b -> b.getCarNo())).forEach(I -> {
                    list.add(I);
                });
                fileName = user.getInputCopName() + "_" + DateUtils.getStringDate() + "_" + dsgApplyCar.getCardType() + "_" + oilComKey + ".xlsx";
                ByteArrayOutputStream bos = new ByteArrayOutputStream();
                ExcelWriter excelWriter = EasyExcel.write(bos).withTemplate(templateFileName).build();
                WriteSheet writeSheet = EasyExcel.writerSheet(0).build();
                serialNumber = 0;
                for (DsgApplyCar dac : list) {
                    serialNumber++;
                    dac.setSerialNumber(serialNumber);
                }
                excelWriter.fill(list, writeSheet);
                Map<String, Object> map = new HashMap<>();
                map.put("date", date);
                map.put("entName", user.getInputCopName());
                map.put("cusName", user.getUserName());
                map.put("checkBatchNo", CollectionUtil.isNotEmpty(list) ? list.get(0).getCheckBatchNo() : "");
                excelWriter.fill(map, writeSheet);
                excelWriter.finish();
                //设置文件名
                ArchiveEntry entry = new ZipArchiveEntry(fileName);
                zous.putArchiveEntry(entry);
                zous.write(bos.toByteArray());
                zous.closeArchiveEntry();
                bos.close();
                log.info("寫Check車牌{}咭{}条", dsgApplyCar.getCardType(), dsgApplyCarList.size());
            }
            if (CollectionUtil.isNotEmpty(dsgApplyStatusList)) {
                dsgApplyStatusService.updateBatchById(dsgApplyStatusList);
                log.info(String.format("回寫Check車牌狀態為進行中%s條", dsgApplyStatusList.size()));
            }
        }
        zous.close();
    }


    static <T> Predicate<T> distinctByKey(Function<? super T, ?> keyExtractor) {
        Map<Object, Boolean> seen = new ConcurrentHashMap<>();
        return t -> seen.putIfAbsent(keyExtractor.apply(t), Boolean.TRUE) == null;
    }

    /**
     * 上FORM（分页）
     *
     * @param dsgApplyCar
     * @return
     */
    @GetMapping(value = "/selectUpFormList")
    @ApiOperation("上FORM（分页）")
    public AjaxResult selectUpFormList(DsgApplyCar dsgApplyCar) {
        // 分页
        Page page = getPage();
        String sort = getParameter("sort");
        List<OrderItem> orderItemList = new ArrayList<>();
        if (StringUtil.isEmpty(sort)) {
            orderItemList.add(new OrderItem().setColumn("b.CREATE_TIME").setAsc(false));
            page.setOrders(orderItemList);
        }
        dsgApplyCar.setEntCode(SingletonLoginUtils.getSystemEntCode());
        dsgApplyCar.setNodeName(WorkflowService3.NODE_UPLOAD_FORM);
        page = service.selectDsgApplyCarList(page, dsgApplyCar);
        // 格式要返回的数据
        AjaxResult ajaxResult = json(MessageConstants.SSO_STATUS_SUCCESS, page.getRecords(), (int) page.getTotal());
        return ajaxResult;
    }

    /**
     * 上載
     *
     * @return
     */
    @PostMapping(value = "/importExcel")
    @ApiOperation("上載")
    @Transactional(rollbackFor = Exception.class)
    public AjaxResult importExcel(@ApiParam(value = "file", name = "file", required = true)
                                  @RequestParam("file") MultipartFile file) throws Exception {
//        AnalysisEventListener<DsgApplyCarModel> dsgApplyCarAnalysisEventListener = EasyExcelUtils.getListener(this.batchInster(), 2);
        EasyExcel.read(file.getInputStream(), DsgApplyCarModel.class, new UploadDsgApplyCar(service, dsgApplyStatusService, caseService, engine, leveldbAccess)).sheet(0).headRowNumber(1).doRead();
        return result(MessageConstants.SSO_STATUS_SUCCESS);
    }

//    private Consumer<List<DsgApplyCarModel>> batchInster() {
//        return dsgApplyCarModels -> {
//            dsgApplyCarModels.forEach(I -> {
//                log.info(I.toString());
//            });
//
//        };
//    }

    @GetMapping(value = "/exportUpFormExcel")
    @ApiOperation(value = "導出上Form")
    @ApiResponses({
            @ApiResponse(response = Boolean.class, code = 1, message = "ok")
    })
    @Transactional(rollbackFor = {Exception.class, RuntimeException.class})
    public void exportUpFormExcel(DsgApplyCar dsgApplyCar, HttpServletResponse response) throws Exception {
        Page page = getPage();  // 分頁
        String sort = getParameter("sort");
        List<OrderItem> orderItemList = new ArrayList<>();
        if (StringUtil.isEmpty(sort)) {
            orderItemList.add(new OrderItem().setColumn("appType").setAsc(false));
            orderItemList.add(new OrderItem().setColumn("reDate").setAsc(false));
            page.setOrders(orderItemList);
        }
        int currentPage = 0;
        SystemAuthorizingUser systemUser = SingletonLoginUtils.getSystemUser();
        dsgApplyCar.setEntCode(systemUser.getOrgCode());
        dsgApplyCar.setNodeName(WorkflowService3.NODE_UPLOAD_FORM);
        dsgApplyCar.setFormStatus(DsgApplyStatus.AppStatus.no.getCode());
        //取文件總數量值
        DsgSysParameter dsgSysParameter = dsgSysParameterService.selectDsgSysParameter("DSG_FILE_IN_OUT", "form");
        int fileQty = 15;
        if (dsgApplyCar != null) {
            fileQty = Integer.parseInt(dsgSysParameter.getParaValue());
            log.info(String.format("每個文件總數據量為%s條", fileQty));
        }
        page.setSize(fileQty);
        List<DsgApplyCar> dsgApplyCarList;
        response.setContentType("application/zip");
        response.setCharacterEncoding("utf-8");
        String fileName = "上FORM_" + systemUser.getOrgCode() + "_" + DateUtils.getStringDate() + ".zip";
        response.setHeader("Content-disposition", "attachment; filename=" + URLEncoder.encode(fileName, "utf-8"));
        OutputStream out = response.getOutputStream();
        //壓縮
        ZipArchiveOutputStream zous = new ZipArchiveOutputStream(out);
        zous.setUseZip64(Zip64Mode.AsNeeded);
        zous.setEncoding("utf-8");
        //
        boolean isExport, isAdd;
        //批次號
        String batchNo = systemUser.getOrgCode() + "-" + DateUtils.getDate();
        String date = DateUtils.getDate();
        Date formDate = new Date();
        String templateFileName = FileUtils.getExcelTemplatePath("upForm.xlsx");
        List<DsgApplyStatus> dsgApplyStatusList = new ArrayList<>();
        do {
            isExport = false;
            isAdd = false;
            fileName = systemUser.getInputCopName() + "_" + DateUtils.getStringDate() + "_" + currentPage + ".xlsx";
            page.setCurrent(++currentPage);
            ByteArrayOutputStream bos = new ByteArrayOutputStream();
            ExcelWriter excelWriter = EasyExcel.write(bos).withTemplate(templateFileName).build();
            WriteSheet writeSheet = EasyExcel.writerSheet(0).build();
            /**
             * CS新申请（记账咭/现金咭）、CS對單加車
             */
            dsgApplyCar.setAppTypeList("1,2,3,7");
            int i = 1;
            dsgApplyCarList = service.selectDsgApplyCarList(page, dsgApplyCar).getRecords();
            if (CollectionUtil.isNotEmpty(dsgApplyCarList)) {
                isAdd = true;
                for (DsgApplyCar dac : dsgApplyCarList) {
                    dac.setSerialNumber(i++);
                    dac.setCardType("SV");
                    dac.setEmbossedName("PDL TEL 23012323");
                    dac.setPin("N");
                    dac.setVehicleEntry("N");
                    dac.setNonFuel("N");
                    if (dac.getIsOdometer() != null) {
                        switch (dac.getIsOdometer()) {
                            case 0:
                                dac.setOdometer("N");
                                break;
                            case 1:
                                dac.setOdometer("Y");
                                break;
                        }
                    }
                    if (dac.getCarOilType() != null) {
                        switch (dac.getCarOilType()) {
                            //汽油
                            case 1:
                                dac.setFuel("G");
                                break;
                            case 2:
                                dac.setFuel("D");
                                break;
                        }
                    }
                    DsgApplyStatus dsgApplyStatus = new DsgApplyStatus();
                    dsgApplyStatus.setOid(dac.getStatusID());
                    dsgApplyStatus.setIsForm(DsgApplyStatus.AppStatus.yes.getCode());
                    dsgApplyStatus.setAppNo(dac.getAppNo());
                    dsgApplyStatus.setFormDate(formDate);
                    dsgApplyStatus.setFormNo(SnowflakeKeyWorker.nextStrId());
                    dsgApplyStatusList.add(dsgApplyStatus);
                }
                excelWriter.fill(new FillWrapper("new", dsgApplyCarList), writeSheet);
                if (!isExport && dsgApplyCarList.size() == fileQty) {
                    isExport = true;
                }
            }
            /**
             * 補咭（记账咭/现金咭）
             * 轉車牌
             * 轉油種
             * 過期補領
             * 取消油咭
             */
            i = 1;
            dsgApplyCar.setAppTypeList("4,5,9,11,13,17,18");
            dsgApplyCarList = service.selectDsgApplyCarList(page, dsgApplyCar).getRecords();
            if (CollectionUtil.isNotEmpty(dsgApplyCarList)) {
                isAdd = true;
                for (DsgApplyCar dac : dsgApplyCarList) {
                    dac.setSerialNumber(i++);
                    dac.setCardType("SV");
                    dac.setEmbossedName("PDL TEL 23012323");
                    dac.setPin("N");
                    dac.setVehicleEntry("N");
                    dac.setNonFuel("N");
                    DsgApplyStatus dsgApplyStatus = new DsgApplyStatus();
                    dsgApplyStatus.setOid(dac.getStatusID());
                    dsgApplyStatus.setIsForm(DsgApplyStatus.AppStatus.yes.getCode());
                    dsgApplyStatus.setAppNo(dac.getAppNo());
                    dsgApplyStatus.setFormDate(formDate);
                    dsgApplyStatus.setFormNo(SnowflakeKeyWorker.nextStrId());
                    dsgApplyStatusList.add(dsgApplyStatus);
                }
                excelWriter.fill(new FillWrapper("change", dsgApplyCarList), writeSheet);
                if (!isExport && dsgApplyCarList.size() == fileQty) {
                    isExport = true;
                }
            }
            /**
             * 修改油咭密碼 14
             * 更改油咭限额 12
             */
            i = 1;
            dsgApplyCar.setAppTypeList("12,14");
            dsgApplyCarList = service.selectDsgApplyCarList(page, dsgApplyCar).getRecords();
            if (CollectionUtil.isNotEmpty(dsgApplyCarList)) {
                isAdd = true;
                for (DsgApplyCar dac : dsgApplyCarList) {
                    dac.setSerialNumber(i++);
                    switch (dac.getAppType()) {
                        case 12:
                            dac.setCardType("Change Profile ID");
                            break;
                        case 14:
                            dac.setCardType("");
                            dac.setLimitId("");
                            dac.setRmk("Reissue Pin");
                            break;
                        case 9:
                            break;
                    }
                    DsgApplyStatus dsgApplyStatus = new DsgApplyStatus();
                    dsgApplyStatus.setOid(dac.getStatusID());
                    dsgApplyStatus.setIsForm(DsgApplyStatus.AppStatus.yes.getCode());
                    dsgApplyStatus.setAppNo(dac.getAppNo());
                    dsgApplyStatus.setFormDate(formDate);
                    dsgApplyStatus.setFormNo(SnowflakeKeyWorker.nextStrId());
                    dsgApplyStatusList.add(dsgApplyStatus);
                }
                excelWriter.fill(new FillWrapper("modify", dsgApplyCarList), writeSheet);
                if (!isExport && dsgApplyCarList.size() == fileQty) {
                    isExport = true;
                }
            }
            Map<String, Object> map = new HashMap<>();
            map.put("date", date);
            map.put("entName", systemUser.getInputCopName());
            map.put("cusName", systemUser.getUserName());
            map.put("accountNo", CollectionUtil.isNotEmpty(dsgApplyCarList) ? dsgApplyCarList.get(0).getAccountNo() : "");
            excelWriter.fill(map, writeSheet);
            excelWriter.finish();
            if(isAdd) {
                //设置文件名
                ArchiveEntry entry = new ZipArchiveEntry(fileName);
                zous.putArchiveEntry(entry);
                zous.write(bos.toByteArray());
                zous.closeArchiveEntry();
            }
            bos.close();
            log.info("寫上FORM{}咭{}条", dsgApplyCar.getCardType(), dsgApplyCarList.size());
        } while (isExport);
        if (CollectionUtil.isNotEmpty(dsgApplyStatusList)) {
            dsgApplyStatusService.updateBatchById(dsgApplyStatusList);
            log.info(String.format("回寫上FORM狀態為是%s條", dsgApplyStatusList.size()));
            for (DsgApplyStatus dsgApplyStatus : dsgApplyStatusList) {
                DsgApproveCase approveCase = caseService.getCase(WorkflowService3.NODE_UPLOAD_FORM, dsgApplyStatus.getAppNo());
                if (approveCase == null) {
                    throw new RRException("對單CASE不存在");
                }
                try {
                    if (DsgApproveCase.Status.started.getCode().intValue() == approveCase.getStatus().intValue()) {
                        engine.forward(approveCase );
                    }
                } catch (Exception e) {
                    log.error("推實例異常：", e);
                    throw new RRException("推實例異常");
                }
            }
        }
        zous.close();
    }

    @PostMapping(value = "/setAddressBatch")
    @ApiOperation("客戶資料-客戶資料-批量设置通讯地址")
    public AjaxResult setAddressBatch(@ApiParam(required = true) @RequestParam List<String> carOidList, @ApiParam(required = true) @RequestParam String addressOid) {
        LambdaUpdateWrapper<DsgApplyCar> wrapper = new LambdaUpdateWrapper<>();
        wrapper.in(DsgApplyCar::getOid, carOidList);
        DsgApplyCar car = new DsgApplyCar();
        car.setCommId(addressOid);
        service.update(car, wrapper);
        return result(MessageConstants.SSO_STATUS_SUCCESS);
    }

    @PostMapping(value = "/setAddress")
    @ApiOperation("对单时设置通讯地址")
    public AjaxResult setAddress(@ApiParam(required = true) @RequestParam String carOid, @ApiParam(required = true) @RequestParam String addressOid) {
        DsgApplyCar car = service.getById(carOid);
        car.setCommId(addressOid);
        service.updateById(car);
        return result(MessageConstants.SSO_STATUS_SUCCESS);
    }

    @PostMapping(value = "/unsetAddress")
    @ApiOperation("对单时去除设置通讯地址")
    public AjaxResult unsetAddress(@ApiParam(required = true) @RequestParam String carOid) {
//        DsgApplyCar car = service.getById(carOid);
//        car.setCommId(null);
        service.removeAddress(carOid);
        return result(MessageConstants.SSO_STATUS_SUCCESS);
    }

    /**
     * 查询列表（分页）
     *
     * @param returnCardRecordDto
     * @return
     */
    @GetMapping(value = "/returnCardList")
    @ApiOperation("查询列表（分页）")
    @ApiResponses(
            @ApiResponse(response = ReturnCardRecordDto.class, code = 0, message = "ok")
    )
    public AjaxResult returnCardList(ReturnCardRecordDto returnCardRecordDto) {
        Page page = getPage();
        String sort = getParameter("sort");
        List<OrderItem> orderItemList = new ArrayList<>();
        OrderItem orderItem = new OrderItem();
        if (StringUtil.isEmpty(sort)) {
            orderItem.setColumn("d.CARD_IN_TIME desc,a.CREATE_TIME");
            orderItem.setAsc(false);
            orderItemList.add(orderItem);
            page.setOrders(orderItemList);
        }
        returnCardRecordDto.setEntCode(SingletonLoginUtils.getSystemEntCode());
        page = service.selectReturnCardList(page, returnCardRecordDto);
        AjaxResult ajaxResult = json(MessageConstants.SSO_STATUS_SUCCESS, page.getRecords(), (int) page.getTotal());
        return ajaxResult;
    }
}
